package com.zt.questionnaire.common.utils.sign;


import com.zt.questionnaire.common.utils.SortUtils;
import com.zt.questionnaire.common.utils.TimeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;


public class MD5<main> {

    static Logger log = LoggerFactory.getLogger(MD5.class);

    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
        "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 将字节数组转换成16进制字符串
     *
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 单个字节转换成16进制的字符串
     *
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;   //取出高4位
        int d2 = n % 16;   //取出低4位
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * MD5编码
     *
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     * @throws UnsupportedEncodingException
     */
    public static String MD5Encode(String origin) {
//    	String md5 = DigestUtils.md5Hex(origin.getBytes("UTF-8"));
//    	return md5;
        byte[] md5Byte = MD5Byte(origin, null);
        if (md5Byte == null) {
            return origin;
        }
        return byteArrayToHexString(md5Byte);
    }

    public static byte[] MD5Byte(String origin, String charsetname) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                return md.digest(origin.getBytes());
            else {
                byte[] bytes = origin.getBytes(charsetname);
                return md.digest(bytes);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    //返回大写MD5
    private static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString.toUpperCase();
    }


    /* 字节数组转成16进制字符串 */
    public static String byte2hex(byte[] bytes) { // 一个字节的数，
        StringBuffer sb = new StringBuffer(bytes.length * 2);
        String tmp = "";
        for (int n = 0; n < bytes.length; n++) {
            // 整数转成十六进制表示
            tmp = (Integer.toHexString(bytes[n] & 0XFF));
            if (tmp.length() == 1) {
                sb.append("0");
            }
            sb.append(tmp);
        }
        return sb.toString().toUpperCase(); // 转成大写
    }

    /**
     * 将hex字符串(16进制字符串)转换成字节数组
     *
     * @param str
     * @return
     */
    public static byte[] hex2byte(String str) {
        if (str == null || str.length() < 2) {
            return new byte[0];
        }
        str = str.toLowerCase();
        int l = str.length() / 2;
        byte[] result = new byte[l];
        for (int i = 0; i < l; ++i) {
            String tmp = str.substring(2 * i, 2 * i + 2);
            result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
        }
        return result;
    }

    /**
     * 将hex字符串(16进制字符串)转换成字节数组
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }


    /**
     * 防止篡改
     * 参数签名
     * <p>
     * 1、按照请求参数名的字母升序排列非空请求参数（包含AccessKey），使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA；
     * 2、在stringA最后拼接上Secretkey得到字符串stringSignTemp；
     * 3、对stringSignTemp进行MD5运算，并将得到的字符串所有字符转换为大写，得到sign值。
     *
     * @param map           参与签名的参数集合，json对象也可以
     * @param appSecretName 秘钥参数的名称
     * @param appSecret     秘钥值
     * @return
     */
    public static String getSign(Map<String, Object> map, String appSecretName, String appSecret) {
        String result = SortUtils.sortMapToStr(map);
        result += "&" + appSecretName + "=" + appSecret;

        log.info("Sign Befor MD5:" + result);
//		System.out.println(result);

        result = MD5.MD5Encode(result).toUpperCase();

        log.info("Sign Result: " + result);
//		System.out.println(result);

        return result;
    }


    public static void main(String[] args) {
        String str = "1111&2451955&22&33&44&55&66&13301810112";
        str = "1111&2455060&测试&210211197403095819&13922871723&渝北测试&妇产科&13632995716";
        System.out.println(MD5Encode(str));
        System.out.println(MD5Encode("JmbAI2020"));

        long currTime = TimeUtils.getCurrTime();
        System.out.println(currTime);
        Map<String, Object> map = new HashMap<>();
        map.put("appKey", "1");
        map.put("timestamp", currTime);
        map.put("img", "http://jsrelease-img.yunmaster.cn/store/img/tongue/jmb_large/original/201812/20181230022223.jpg");
        System.out.println(getSign(map, "appSecret", "1111"));


    }

}
